
/**
 * 
 * 封装:
 * 封装的本质是把抽象出来的属性和对方法组合在一起,只对外暴露指定的接口，
 * 且属性值被保护在内部, 只有通过接口进行修改和读取，不用考虑内部如何实现。
 * 函数就是最基础的代码封装形式，面向对象思想中的封装仍以函数为基础
 * 
 * 继承:
 * 从已有类中派生出新的类。继承可以使得子类具有父类的各种属性和方法。
 * 而不需要再次编写相同的代码。在令子类别继承父类别的同时，可以重新定义某些属性，
 * 并重写某些方法，即覆盖父类原有的属性和方法，使其获得与父类不同的功能。
 * 子类继承父类后，子类具有父类属性和方法，然而也同样具备自己所独有的属性和方法
 * 代码得到了共享。提高了代码的重用性，避免了重复书写
 * 
 * 多态：
 * 相同的事物，调用其相同的方法，参数也相同时，作用在不同的对象表现的行为却不同
 * 实现了方法的个性化，不同的子类根据具体状况可以实现不同的方法
 * 子类对父类的方法进行重写，调用这个方法时，会默认执行子类的方法，即实现多态
 * 参数个数不同, 执行不同的代码 :利用arguments.length判断来实现
 */
//es6类
console.log("=============================封装============================")
class Person {

    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    set userName(n){
        this.name = n 
    }
    get userName(){
        return this.name+" get 方式"
    }
    getInfo(){
    let {name,age} = this;
        return {name,age};
    }
    
    static sayHi(){ //这里使用了static对sayHi方法对其进行了访问权限的封装。
        console.log("Hi");
    }
    sayHello() {
        console.log(`我叫${this.name}, 今年${this.age}岁`);
    }
}
    
    let Tom= new Person("Tom",18);
    
    // Tom.sayHi(); // Tom.sayHi is not a function
    
    Tom.getInfo(); // {name: "Tom", age: 18}
    console.log(Tom.userName)//Tom.name
    
    Person.sayHi(); // Hi

//继承
console.log("=============================继承============================")
class Teacher extends Person {

    constructor(name, age, course) {
        super(name, age);
        this.course = course;
    }
    
    // 重写父类的方法
    sayHello() {
        // super.sayHello()
        console.log(`我叫${this.name}, 今年${this.age}岁, 教${this.course}`);
    }
        
}
        
const Jack = new Teacher("Jack", 30, "English");

Jack.sayHello(); // 我叫Jack, 今年30岁

console.log("=============================多态============================")
const Enum = {
    DOG:"dog",
    CAT:"cat",
    PIG:"pig"
}
class Animal{
    eat(){
        throw new Error("eat ")
    }
    run(){}
}

class Dog extends Animal{
    eat(){
        console.log("狗吃")
    }
    run(){
        console.log("狗跑");
    }
}

class Pig extends Animal{
    eat(a){
        console.log("猪吃",a)
    }
    run(){
        console.log("猪跑");
    }
}

class Cat extends Animal{
    eat(){//不重写会报错
        if(arguments.length==0){
            console.log("猫吃,无参数")
        }else if(arguments.length==1){
            console.log("猫吃，1个参数",arguments[0])
        }else  if(arguments.length==2){
            console.log("猫吃，2个参数",arguments[0],arguments[1])
        }
    }
    run(){
        console.log("猫跑");
    }
}



class Test{
    constructor(type){
        switch (type) {
            case Enum.CAT:
                return new Cat()
            case Enum.PIG:
                return new Pig()
            case Enum.DOG:
                return new Dog()
            default:
                return null
        }
    }
}

// Animal animal = new Test(Enum.CAT)
const animal = new Test(Enum.CAT)
animal.eat("饼干")